//Random Game Engine
//Copyright (C) 2013  Nikolay Dionisov

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "Framework.h"

//managers which need to get loaded
#include "..\Utilities\MemoryPool.h"
#include "..\Managers\Platform Manager\WindowsPlatform.h"

namespace re
{
	namespace core
	{
		//----------------------------------------------------------------------------------------------------------------
		//Allocate the managers and save a pointer to them
		//----------------------------------------------------------------------------------------------------------------
		void Framework::InitializeManagers(ManagerContainer* managers)
		{
			//save the pointer
			pmanagers_ = managers;
			//Allocate the platform manager
#ifdef WIN32
			platform_manager = RE_NEW WindowsPlatform;
#elif LINUX
			platform_manager = NULL; // linux not supported
#else
			#error "Currently Supported only Windows. Please move to a windows platform."
#endif
			platform_manager->SetManagerContainer(managers);
			pmanagers_->environment_manager = RE_NEW EnvironmentManager;
			pmanagers_->task_manager = RE_NEW TaskManager;
			pmanagers_->state_manager = RE_NEW StateManager;

			thread_pool_.AllocateThreads(managers);
		}
		void Framework::MainLoop()
		{
			while(1)
			{
				platform_manager->VProcessMessages();
				sheduler_.UpdateSystems(pmanagers_);

				//is there a system which think we should quit?
				if(pmanagers_->environment_manager->GetExitFlag())
				{
					break;
				}
				pmanagers_->task_manager->TryDoTask();
			}
		}
		//*******************************************************************************************
		//***  Send ShutDown tasks to all systems and wait till all alive tasks are completed  ******
		//*******************************************************************************************
		void Framework::ShutDown()
		{
			//shutdown the systems
			sheduler_.RemoveSystems(pmanagers_);
			//remove any framework related memory(windows for example)
			//release the threads
			thread_pool_.Release(pmanagers_->task_manager);
			if(platform_manager != 0)
			{
				delete platform_manager;
			}
		}
		void Framework::RunLogic(ILogic* logic)
		{
			//load the main menu(a scene which logic will tell us to load)
			logic->StartUp(this);
			//now add the logic as a normal system/process.
			//this way it will get some procesor time and navigate the engine
			AddSystem(logic, logic->GetPriority());
			//now everything should be set up. Create the rendering windows
			IWindow* win = platform_manager->VCreateWindow(pmanagers_->environment_manager->GetApplicationName());
			//pmanagers_->service_manager->MakeServiceRequest(
		}
		ManagerContainer* Framework::GetManagerContainer()
		{
			return pmanagers_;
		}

		
		bool Framework::LoadSystem(std::wstring& source, int priority)
		{
			ISystem* sys = platform_manager->LoadModule(source);
			//TODO: Maaintain a list of dll systems.Thy need to be freed at the end.
			if(sys != NULL)
			{
				AddSystem(sys, priority);
				return true;
			}else
			{
				ASSERT("Could not load the requested system.");
				return false;
			}
		}
		void Framework::AddSystem(ISystem* system, int priority)
		{
			if(system == NULL)
			{
				return;
			}
			//systems list. It may cause some method to malfunction.

			//Priority shoud be changable
			sheduler_.AddSystem(system, priority);
			
			//module need to register its services and state changes
			system->Setup(pmanagers_);
		}

	
	}
}